package com.bzkj.framework.aspectj;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.bzkj.common.annotation.LogC;
import com.bzkj.common.core.domain.AjaxResult;
import com.bzkj.common.core.domain.model.LoginUser;
import com.bzkj.common.enums.BusinessStatus;
import com.bzkj.common.enums.BusinessType;
import com.bzkj.common.enums.HttpMethod;
import com.bzkj.common.filter.PropertyPreExcludeFilter;
import com.bzkj.common.utils.ObjectMapConverter;
import com.bzkj.common.utils.SecurityUtils;
import com.bzkj.common.utils.ServletUtils;
import com.bzkj.common.utils.StringUtils;
import com.bzkj.common.utils.ip.AddressUtils;
import com.bzkj.common.utils.ip.IpUtils;
import com.bzkj.framework.manager.AsyncManager;
import com.bzkj.framework.manager.factory.AsyncFactory;
import com.bzkj.system.domain.SysBasicDataLog;
import com.bzkj.system.domain.SysOperOrderLog;
import com.bzkj.system.service.ISysBasicDataLogService;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.NamedThreadLocal;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

import static org.springframework.util.StringUtils.capitalize;

/**
 * 操作日志记录处理
 *
 * @author ruoyi
 */
@Aspect
@Component
public class LogAspectC {
    private static final Logger log = LoggerFactory.getLogger(LogAspectC.class);


    @Resource
    private ISysBasicDataLogService basicDataLogService;

    /**
     * 排除敏感属性字段
     */
    public static final String[] EXCLUDE_PROPERTIES = {"password", "oldPassword", "newPassword", "confirmPassword"};

    /**
     * 计算操作消耗时间
     */
    private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Cost Time");

    // SpEL 解析器
    private final ExpressionParser parser = new SpelExpressionParser();

    @Around(value = "@annotation(logC)", argNames = "pjp,logC")
    public Object handleLog(ProceedingJoinPoint pjp, LogC logC) throws Throwable {
        TIME_THREADLOCAL.set(System.currentTimeMillis());
        // 用于存储被代理方法的执行结果
        Object result;
        SysBasicDataLog basicDataLog = null;
        try {
            // 获取当前的用户
            LoginUser loginUser = SecurityUtils.getLoginUser();

            // 创建操作日志对象
            basicDataLog = createOperLog(pjp, loginUser, logC);

            // 设置方法名称
            setMethodInfo(pjp, basicDataLog);

            // 处理设置注解上的参数
            result = getControllerMethodDescription(pjp, logC, basicDataLog, null);

        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("异常信息: {}", exp.getMessage(), exp);
            if (basicDataLog != null) {
                basicDataLog.setStatus(BusinessStatus.FAIL.ordinal());
                basicDataLog.setErrorMsg(exp.getMessage());
                AsyncManager.me().execute(AsyncFactory.recordBasicDataOper(basicDataLog));
            }
            throw exp; // 重新抛出异常，确保调用方能够捕获到异常
        } finally {
            TIME_THREADLOCAL.remove();
        }

        // 返回被代理方法的执行结果
        return result;
    }

    /**
     * 创建操作日志对象并设置基本信息
     */
    private SysBasicDataLog createOperLog(ProceedingJoinPoint joinPoint, LoginUser loginUser, LogC logC) {
        SysBasicDataLog operLog = new SysBasicDataLog();
        operLog.setStatus(BusinessStatus.SUCCESS.ordinal());

        // 请求的地址--ip
        String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
        operLog.setOperIp(ip);

        // 请求的地址--url
        operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));

        // 操作人
        if (loginUser != null) {
            operLog.setOperName(loginUser.getUsername());
        }
        //登录地址
        operLog.setOperLocation(AddressUtils.getRealAddressByIP(ip));

        // 设置action动作
        operLog.setBusinessType(logC.businessType().ordinal());
        // 设置标题
        operLog.setTitle(logC.title());
        // 设置操作人类别
        operLog.setOperatorType(logC.operatorType().ordinal());

        return operLog;
    }


    /**
     * 设置方法信息
     *
     * @param joinPoint 目标方法的连接点
     * @param operLog   操作日志记录表
     */
    private void setMethodInfo(ProceedingJoinPoint joinPoint, SysBasicDataLog operLog) {
        String className = joinPoint.getTarget().getClass().getName();//类名
        String methodName = joinPoint.getSignature().getName();//方法名
        operLog.setMethod(className + "." + methodName + "()");

        // 设置请求方式
        operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
    }

    /**
     * 获取注解中对方法的描述信息 用于Controller层注解
     */
    public Object getControllerMethodDescription(ProceedingJoinPoint joinPoint, LogC log, SysBasicDataLog basicDataLog, Object jsonResult) throws Throwable {
        Object result;
        // 设置action动作
        if (log.businessType().ordinal() == BusinessType.UPDATE.ordinal()) {
            //修改操作日志处理
            result = processUpdateLog(joinPoint, log, basicDataLog, jsonResult);
        } else {
            // 1. 获取方法参数名和值
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            String[] paramNames = signature.getParameterNames();
            Object[] args = joinPoint.getArgs();

            StringBuilder fieldNames = new StringBuilder();
            // 2. 解析 SpEL（如果 content 不为空）
            String logContent = log.content();
            if (!logContent.isEmpty()) {
                fieldNames.append(getString(args, paramNames, logContent));
            }
            // 3. 解析 paramField 指定的字段（如 "warehouse.stoName"）
            String param = log.paramField();
            if (!param.isEmpty()) {
                String[] parts = param.split("\\.");
                if (parts.length == 2) {
                    String paramName = parts[0];  // 参数名，如 "warehouse"
                    String fieldName = parts[1]; // 字段名，如 "stoName"
                    // 找到对应的参数对象
                    Object targetParam = null;
                    for (int i = 0; i < paramNames.length; i++) {
                        if (paramNames[i].equals(paramName)) {
                            targetParam = args[i];
                            break;
                        }
                    }
                    // 反射获取字段值
                    if (targetParam != null) {
                        try {
                            Object fieldValue = targetParam.getClass()
                                    .getMethod("get" + capitalize(fieldName))
                                    .invoke(targetParam);
                            System.out.println("[LogC] " + fieldName + ": " + fieldValue);
                            fieldNames.append("名称：" + fieldValue);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            //4解析list类型入参
            fieldNames.append(extractList(args));
            //执行原有方法并获取返回结果
            result = joinPoint.proceed();
            AjaxResult ajaxResult = (AjaxResult) result;
            if (ajaxResult.isSuccess()) {
                basicDataLog.setOperDesc(basicDataLog.getOperName() + log.businessType().getDescription() + basicDataLog.getTitle() + ", " + fieldNames + "。");
            } else {
                basicDataLog.setStatus(BusinessStatus.FAIL.ordinal());
                basicDataLog.setErrorMsg(ajaxResult.get("msg").toString());
            }
            basicDataLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());
            AsyncManager.me().execute(AsyncFactory.recordBasicDataOper(basicDataLog));
        }
        return result;
    }

    /**
     * 处理请求
     *
     * @param joinPoint    切点
     * @param log          日志注解
     * @param basicDataLog 操作日志
     * @param jsonResult   返回结果
     */
    public Object processUpdateLog(ProceedingJoinPoint joinPoint, LogC log, SysBasicDataLog basicDataLog, Object jsonResult) throws Throwable {
        // 提取主要所在的表
        String tableName = log.tableNames();
        // 提取主要表主键
        String pkFieldNames = log.pkFieldNames();
        String idFieldName = log.idFieldName();
        //提取主要表的主键值
        // 提取关联表
        String detailTable = log.detailTable();
        // 提取表头表和关联表的关联键
        String detailIdField = log.associatedIdField();
        // 提取关联表主键
        String detailPkField = log.detailPkField();
        // 获取方法参数，解析主键 ID
        Object[] args = joinPoint.getArgs();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();//获取方法名
        //获取主键字段值
        Object primaryKey = extractPrimaryKey(pkFieldNames, args, method);
        //处理List入参
        Object extractList = extractList(args);
        // 1. 获取方法参数名和值
        String[] paramNames = signature.getParameterNames();
        // 2. 解析 SpEL（如果 content 不为空）
        String pkFileds = log.pkFileds();//多字段
        String content = log.content();
        pkFileds = getString(args, paramNames, pkFileds);
        content = getString(args, paramNames, content);
        // 获取旧数据
        long sqlStart = System.currentTimeMillis();
        //查询主表数据
        Map<String, Object> oldHeader = new HashMap<>();
        String[] pkFiledsArr = pkFileds.split(",");
        String[] pkFieldNamesArr = pkFieldNames.split(",");
        String[] strings = Arrays.stream(pkFiledsArr)
                .filter(i -> StringUtils.isNotBlank(i) && !i.equals("null"))
                .toArray(String[]::new);
        if (pkFieldNamesArr.length != strings.length) {
            pkFieldNamesArr = Arrays.copyOf(pkFieldNamesArr, strings.length);
        }
        if (StringUtils.isBlank(pkFileds)) {
            oldHeader = basicDataLogService.selectWarehouseByPk(pkFieldNames, tableName, primaryKey);
        } else {
            oldHeader = basicDataLogService.selectWarehouseByMultiPk(pkFieldNamesArr, tableName, strings);
        }
        //查询关联表数据
        List<Map<String, Object>> oldDetails = detailTable.isEmpty() ? null : basicDataLogService.selectRelatedByPk(detailIdField, detailTable, primaryKey);
        long sqlEnd = System.currentTimeMillis();

        // 执行原方法（更新数据库）
        Object result = joinPoint.proceed();

        // 计算耗时
        basicDataLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get() - (sqlEnd - sqlStart));

        // 查询新数据
        //查询主表数据
        Map<String, Object> newHeader = new HashMap<>();
        if (StringUtils.isBlank(pkFileds)) {
            newHeader = basicDataLogService.selectWarehouseByPk(pkFieldNames, tableName, primaryKey);
        } else {

            newHeader = basicDataLogService.selectWarehouseByMultiPk(pkFieldNamesArr, tableName, strings);
        }
        //查询关联表数据
        List<Map<String, Object>> newDetails = detailTable.isEmpty() ? null : basicDataLogService.selectRelatedByPk(detailIdField, detailTable, primaryKey);

        // 获取字段翻译集
        Map<String, String> fieldTranslationMap = basicDataLogService.getFieldTranslations(tableName)
                .stream()
                .collect(Collectors.toMap(m -> m.get("field_name"), m -> m.get("field_cn_name")));

        // 比较并翻译字段
        if(Objects.nonNull(oldHeader)&&Objects.nonNull(newHeader)){
            Map<String, Map<String, String>> translateChanges = translateChanges(fieldTranslationMap, oldHeader, newHeader, tableName);
            //设置操作表述，从什么修改成了什么 此处可能会有多个字段被修改
            StringBuilder sb = new StringBuilder("");
            int size = translateChanges.size();
            int count = 0;
            for (Map.Entry<String, Map<String, String>> tc : translateChanges.entrySet()) {
                String key = tc.getKey();//修改的字段
                Map<String, String> value = tc.getValue();//修改前后的值
                String newValue = value.get("newValue");//修改后的值
                String oldValue = value.get("oldValue");//修改前的数据
                count++;
                //判断是否是最后一个
                if (count == size) {
                    sb.append("将【").append(key).append("】从").append(oldValue).append("修改成").append(newValue);
                } else {
                    sb.append("将【").append(key).append("】从").append(oldValue).append("修改成").append(newValue).append(";");
                }
            }
            //判断入参字段是否为空
            Object str = newHeader.get(pkFieldNames);
            if (Objects.isNull(str)) {
                str = newHeader.get(idFieldName);
            }
            if (StringUtils.isBlank(content)) {
                basicDataLog.setOperDesc(basicDataLog.getOperName() + log.businessType().getDescription() + basicDataLog.getTitle() + ",目标对象：" + str + "。");
            } else {
                basicDataLog.setOperDesc(basicDataLog.getOperName() + log.businessType().getDescription() + basicDataLog.getTitle() + content + "。");
            }
            basicDataLog.setDetailType("header");
            basicDataLog.setOperationDetail(JSONObject.toJSONString(translateChanges));
        }
        // 存储操作记录
        Long parentId = basicDataLogService.insertOperlog(basicDataLog);
        if (oldDetails != null) {
            for (Map<String, Object> oldDetail : oldDetails) {
                // 获取字段翻译集
                Map<String, String> fieldTranslationMapA = basicDataLogService.getFieldTranslations(detailTable)
                        .stream()
                        .collect(Collectors.toMap(m -> m.get("field_name"), m -> m.get("field_cn_name")));
                assert newDetails != null;

                newDetails.forEach(newDetail -> {
                    if (newDetail.get(detailPkField).equals(oldDetail.get(detailPkField))) {
                        basicDataLog.setDetailType("detail");
                        basicDataLog.setParentId(parentId);
                        //判断关联表是否被修改
                        Map<String, Map<String, String>> detailChangeMap = translateChanges(fieldTranslationMapA, oldDetail, newDetail, tableName);
                        if (!detailChangeMap.isEmpty()) {
                            basicDataLog.setOperationDetail(JSONObject.toJSONString(detailChangeMap));
                            basicDataLogService.insertOperlog(basicDataLog);
                        }
                    }
                });
            }
        }
        return result;
    }

    private String getString(Object[] args, String[] paramNames, String pkFileds) {
        if (!pkFileds.isEmpty()) {
            StandardEvaluationContext context = new StandardEvaluationContext();
            for (int i = 0; i < paramNames.length; i++) {
                context.setVariable(paramNames[i], args[i]); // 设置变量，如 #warehouse
            }
            Expression exp = parser.parseExpression(pkFileds);
            pkFileds = exp.getValue(context, String.class); // 计算 SpEL 表达式
        }
        return pkFileds;
    }

    private Object extractPrimaryKey(String idField, Object[] args, Method method) {
        for (Object arg : args) {
            //判断arg是否是map类型
            if (arg instanceof Map) {
                Map<?, ?> map = (Map<?, ?>) arg;
                Map<?, ?> header = (Map<?, ?>) map.get("header");
                if (header != null) {
                    return header.get(idField);
                }
            }
            //判断arg是否是对象类型,将idField转为驼峰进行匹配
            if (arg != null) {
                String uncapitalize = idField;
                //idField下划线转驼峰
                if (idField.contains("_")) {
                    uncapitalize = StringUtils.uncapitalize(
                            Arrays.stream(idField.split("_"))
                                    .map(StringUtils::capitalize)
                                    .collect(Collectors.joining()));
                }
                if (arg instanceof String || arg instanceof Integer) {
                    ParameterNameDiscoverer parameterNames = new DefaultParameterNameDiscoverer();
                    String[] namesParameterNames = parameterNames.getParameterNames(method);
                    if (namesParameterNames != null) {
                        List<String> list = Arrays.asList(namesParameterNames);
                        int index = list.indexOf(uncapitalize);
                        return args[index];
                    }
                } else {
                    //对象转换成map
                    Map<String, Object> objectMap = ObjectMapConverter.toMap(arg);
                    return objectMap.get(uncapitalize);
                }
            }
        }
        return null;
    }

    /**
     * 处理list入参
     *
     * @param args
     * @return
     */
    private Object extractList(Object[] args) {
        StringBuilder fieldNames = new StringBuilder();
        for (Object arg : args) {
            if (arg != null) {
                if (arg instanceof List) {
                    // 特殊处理List参数
                    fieldNames.append("目标对象: ").append(JSON.toJSONString(arg)).append("; ");
                }
            }
        }
        return fieldNames;
    }

    /**
     * 生成修改日志，翻译字段
     */
    private Map<String, Map<String, String>> translateChanges(Map<String, String> fieldTranslationMap,
                                                              Map<String, Object> oldData, Map<String, Object> newData, String tableName) {
        Map<String, Map<String, String>> changes = new HashMap<>();
        for (String key : newData.keySet()) {
            if (oldData != null && oldData.containsKey(key) && !Objects.equals(oldData.get(key), newData.get(key))) {
                String fieldDesc = fieldTranslationMap.get(key);
                if (fieldDesc != null) {
                    HashMap<String, String> detailMap = new HashMap<>();
                    String oldString = oldData.get(key).toString();//旧数据 修改前
                    String newString = newData.get(key).toString();//新数据 修改后
                    HashMap<String, String> stringHashMap = statusConvert(key, oldString, newString, detailMap, tableName);
                    if (stringHashMap.isEmpty()) {
                        detailMap.put("oldValue", oldString);
                        detailMap.put("newValue", newString);
                    } else {
                        detailMap = stringHashMap;
                    }
                    changes.put(fieldDesc, detailMap);
                }
            }
        }
        return changes;
    }

    /**
     * 状态转换处理
     *
     * @return
     */
    private HashMap<String, String> statusConvert(String key, String oldData, String newData, HashMap<String, String> detailMap,
                                                  String tableName) {
        //统一处理 1 启用 0 禁用的状态
        if ((tableName.equals("basic_sto_stock") && (key.equals("wms_enable_state") || key.equals("enable_state"))) ||//仓库
                (tableName.equals("sys_post") && key.equals("status")) || //岗位管理
                ((tableName.equals("basic_sto_area") || tableName.equals("basic_sto_unit")) && key.equals("enable_state")) || //货区、货位
                (key.equals("is_translated")) || //字段翻译映射
                ((tableName.equals("wms_basic_bills_type") || tableName.equals("bills_type_map") || tableName.equals("wms_bills_type_bills_status") || tableName.equals("wms_rule"))
                        && key.equals("enable_status")) ||//单据分类、单据类型
                (tableName.equals("ncc_basic_sku_info") && key.equals("restrictions")) ||
                (tableName.equals("sys_menu") && (key.equals("is_frame") || key.equals("is_cache") || key.equals("visible") || key.equals("status")))||//菜单管理
                (tableName.equals("sys_role")&&(key.equals("menu_check_strictly")||key.equals("dept_check_strictly")))
        ) {
            if (oldData.equals("1")) {
                detailMap.put("oldValue", "启用");
            } else {
                detailMap.put("oldValue", "禁用");
            }
            if (newData.equals("1")) {
                detailMap.put("newValue", "启用");
            } else {
                detailMap.put("newValue", "禁用");
            }
        }
        //统一处理 1禁用 0启用/1禁用 2启用的状态
        if (((tableName.equals("sys_role") || tableName.equals("sys_user") || tableName.equals("sys_dict_type")|| tableName.equals("sys_dict_data")) && key.equals("status")) ||
                ((tableName.equals("ncc_basic_user_info") || tableName.equals("ncc_basic_customer") || tableName.equals("ncc_basic_supplier") || tableName.equals("ncc_material_manufacturer"))
                        && key.equals("enablestate")) ||//ncc人员、客户、供应商、生产商信息
                ((tableName.equals("ncc_basic_sto_stock") || tableName.equals("ncc_basic_sku_info") || tableName.equals("ncc_basic_sku_type"))
                        && key.equals("enable_state")) ||//ncc仓库、商品信息、商品分类
                (tableName.equals("ncc_basic_dept") && key.equals("enableState")) //ncc部门
        ) {
            if (oldData.equals("1")) {
                detailMap.put("oldValue", "禁用");
            } else {
                detailMap.put("oldValue", "启用");
            }
            if (newData.equals("1")) {
                detailMap.put("newValue", "禁用");
            } else {
                detailMap.put("newValue", "启用");
            }
        }
        //参数设置状态转换
        if (tableName.equals("sys_config") && key.equals("config_type")) {
            if (oldData.equals("Y")) {
                detailMap.put("oldValue", "内置");
            } else {
                detailMap.put("oldValue", "不内置");
            }
            if (newData.equals("Y")) {
                detailMap.put("newValue", "内置");
            } else {
                detailMap.put("newValue", "不内置");
            }
        }

        if (tableName.equals("wms_sto_stock") && key.equals("freeze_status")) {
            if (oldData.equals("1")) {
                detailMap.put("oldValue", "冻结");
            } else {
                detailMap.put("oldValue", "解冻");
            }
            if (newData.equals("1")) {
                detailMap.put("newValue", "冻结");
            } else {
                detailMap.put("newValue", "解冻");
            }
        }
        //数据范围（1：全部数据权限 2：自定数据权限 3：本部门数据权限 4：本部门及以下数据权限 5:仅本人数据权限）
        if (tableName.equals("sys_role") && key.equals("data_scope")) {
            if (oldData.equals("1")) {
                detailMap.put("oldValue", "全部数据权限");
            }
            if (oldData.equals("2")) {
                detailMap.put("oldValue", "自定数据权限");
            }
            if (oldData.equals("3")) {
                detailMap.put("oldValue", "本部门数据权限");
            }
            if (oldData.equals("4")) {
                detailMap.put("oldValue", "本部门及以下数据权限");
            }
            if (oldData.equals("5")) {
                detailMap.put("oldValue", "仅本人数据权限");
            }
            if (newData.equals("1")) {
                detailMap.put("newValue", "全部数据权限");
            }
            if (newData.equals("2")) {
                detailMap.put("newValue", "自定数据权限");
            }
            if (newData.equals("3")) {
                detailMap.put("newValue", "本部门数据权限");
            }
            if (newData.equals("4")) {
                detailMap.put("newValue", "本部门及以下数据权限");
            }
            if (newData.equals("5")) {
                detailMap.put("newValue", "仅本人数据权限");
            }
        }
        if (tableName.equals("sys_user") && key.equals("sex")) {
            if (oldData.equals("0")) {
                detailMap.put("oldValue", "男");
            } else if (oldData.equals("1")) {
                detailMap.put("oldValue", "女");
            } else {
                detailMap.put("oldValue", "未知");
            }
            if (newData.equals("0")) {
                detailMap.put("newValue", "男");
            } else if (newData.equals("1")) {
                detailMap.put("newValue", "女");
            } else {
                detailMap.put("newValue", "未知");
            }
        }
        return detailMap;
    }

    /**
     * 获取请求的参数，放到log中
     *
     * @param operLog 操作日志
     * @throws Exception 异常
     */
    private void setRequestValue(JoinPoint joinPoint, SysOperOrderLog operLog, String[] excludeParamNames) throws Exception {
        Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
        String requestMethod = operLog.getRequestMethod();
        if (StringUtils.isEmpty(paramsMap)
                && (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))) {
            String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
            operLog.setOperParam(StringUtils.substring(params, 0, 2000));
        } else {
            operLog.setOperParam(StringUtils.substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter(excludeParamNames)), 0, 2000));
        }
    }

    /**
     * 参数拼装
     */
    private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) {
        StringBuilder params = new StringBuilder();
        if (paramsArray != null && paramsArray.length > 0) {
            for (Object o : paramsArray) {
                if (StringUtils.isNotNull(o) && !isFilterObject(o)) {
                    try {
                        String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter(excludeParamNames));
                        params.append(jsonObj).append(" ");
                    } catch (Exception e) {
                    }
                }
            }
        }
        return params.toString().trim();
    }

    /**
     * 忽略敏感属性
     */
    public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames) {
        return new PropertyPreExcludeFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames));
    }

    /**
     * 判断是否需要过滤的对象。
     *
     * @param o 对象信息。
     * @return 如果是需要过滤的对象，则返回true；否则返回false。
     */
    @SuppressWarnings("rawtypes")
    public boolean isFilterObject(final Object o) {
        Class<?> clazz = o.getClass();
        if (clazz.isArray()) {
            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
        } else if (Collection.class.isAssignableFrom(clazz)) {
            Collection collection = (Collection) o;
            for (Object value : collection) {
                return value instanceof MultipartFile;
            }
        } else if (Map.class.isAssignableFrom(clazz)) {
            Map map = (Map) o;
            for (Object value : map.entrySet()) {
                Map.Entry entry = (Map.Entry) value;
                return entry.getValue() instanceof MultipartFile;
            }
        }
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
                || o instanceof BindingResult;
    }

    public static String camelToSnake(String str) {
        if (str == null || str.isEmpty()) {
            return str;
        }

        StringBuilder result = new StringBuilder();
        result.append(Character.toLowerCase(str.charAt(0)));

        for (int i = 1; i < str.length(); i++) {
            char currentChar = str.charAt(i);
            if (Character.isUpperCase(currentChar)) {
                // 处理连续大写字母情况（如"HTTP"）
                if (i > 0 && !Character.isUpperCase(str.charAt(i - 1))) {
                    result.append('_');
                }
                result.append(Character.toLowerCase(currentChar));
            } else {
                result.append(currentChar);
            }
        }

        return result.toString();
    }

}
